---
type: tutorial
title: Generar páginas de etiquetas
i18nReady: true
description: |-
  Tutorial: Crea tu primer blog con Astro —
  Utiliza getStaticPaths() para crear varias páginas (rutas) a la vez
---
import Box from '~/components/tutorial/Box.astro';
import Checklist from '~/components/Checklist.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import Option from '~/components/tutorial/Option.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';



<PreCheck>
  - Crear una página para generar varias páginas
  - Especificar qué rutas de página construir, y pasa a cada página sus propios props
</PreCheck>

## Enrutamiento dinámico de páginas

Puedes crear conjuntos completos de páginas de forma dinámica utilizando archivos `.astro` que exporten una función `getStaticPaths()`. 

## Crea páginas dinámicamente

1. Crea un nuevo archivo en `src/pages/tags/[tag].astro`. (Tendrás que crear una nueva carpeta) Observa que el nombre del archivo (`[tag].astro`) utiliza corchetes. Pega el siguiente código en el archivo:

    ```astro title="src/pages/tags/[tag].astro"
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';

    export async function getStaticPaths() {
      return [
        { params: { tag: "astro" } },
        { params: { tag: "éxitos" } },
        { params: { tag: "comunidad" } },
        { params: { tag: "bloguear" } },
        { params: { tag: "contratiempos" } },
        { params: { tag: "aprender en público" } },
      ];
    }

    const { tag } = Astro.params;
    ---
    <BaseLayout pageTitle={tag}>
      <p>Entradas etiquetadas con {tag}</p>
    </BaseLayout>
    ```

    La función `getStaticPaths` devuelve un array de rutas de páginas, y todas las páginas en esas rutas usarán la misma plantilla definida en el fichero.

2. Si has personalizado las entradas de tu blog, sustituye los valores de las etiquetas individuales (por ejemplo, "astro", "éxitos", "comunidad", etc.) por las etiquetas utilizadas en tus propias entradas.

3. Asegúrate de que cada entrada del blog contiene al menos una etiqueta, escrita como un array, por ejemplo `tags: ["bloguear"]`.

4. Visita `http://localhost:4321/tags/astro` en la vista previa de tu navegador y deberías ver una página, generada dinámicamente a partir de `[tag].astro`. Comprueba que también tienes páginas creadas para cada una de tus etiquetas en `/tags/éxitos`, `/tags/comunidad`, y `/tags/aprender%20en%20publico`, etc., o en cada una de tus etiquetas personalizadas. Es posible que primero tengas que salir y reiniciar el servidor de desarrollo para ver estas nuevas páginas.


## Utiliza props en rutas dinámicas

1. Añade los siguientes props a tu función `getStaticPaths()` para que los datos de todas las entradas de tu blog estén disponibles para cada ruta de página.

    Asegúrate de dar a cada ruta de tu array los nuevos props, y luego haz que esos props estén disponibles para tu plantilla de componentes fuera de tu función.

    ```astro title="src/pages/tags/[tag].astro" ins={5,18} "props: {posts: allPosts}" 
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';

    export async function getStaticPaths() {
      const allPosts = await Astro.glob('../posts/*.md');

      return [
        {params: {tag: "astro"}, props: {posts: allPosts}},
        {params: {tag: "éxitos"}, props: {posts: allPosts}},
        {params: {tag: "comunidad"}, props: {posts: allPosts}},
        {params: {tag: "bloguear"}, props: {posts: allPosts}},
        {params: {tag: "contratiempos"}, props: {posts: allPosts}},
        {params: {tag: "aprender en público"}, props: {posts: allPosts}}
      ]
    }
    
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    ---
    ```

2. Filtra tu lista de entradas para incluir solo las entradas que contengan la etiqueta propia de la página.

    ```astro title="/src/pages/tags/[tag].astro" ins={4}
    ---
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    const filteredPosts = posts.filter((post) => post.frontmatter.tags?.includes(tag));
    ---
    ```

3. Ahora puedes actualizar tu plantilla HTML para mostrar una lista de cada entrada del blog que contenga la etiqueta propia de la página. Añade el siguiente código a `[tag].astro`:

    ```astro title="src/pages/tags/[tag].astro" ins={3-5}
    <BaseLayout pageTitle={tag}>   
      <p>Entradas etiquetadas con {tag}</p>
      <ul>
        {filteredPosts.map((post) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
      </ul>
    </BaseLayout>
    ```

4. Incluso puedes refactorizar esto para usar tu componente `<BlogPost />` en su lugar. (No olvides importar este componente en la parte superior de `[tag].astro`).

    ```astro title="src/pages/tags/[tag].astro" del={4} ins={5}
    <BaseLayout pageTitle={tag}>
      <p>Entradas etiquetadas con {tag}</p>
      <ul>
        {filteredPosts.map(post => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
        {filteredPosts.map(post => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
      </ul>
    </BaseLayout>
    ```

5. Verifica la vista previa de tu navegador para las páginas de etiquetas individuales, y ahora deberías ver una lista de todas tus entradas de blog que contienen esa etiqueta particular.

<Box icon="question-mark">

### Analiza el patrón

Para cada uno de los siguientes, indica si el código está escrito **dentro** de la función `getStaticPath()`, o **fuera** de ella.

1. La llamada `Astro.glob()` para recibir información sobre todos tus archivos `.md` para pasar a cada ruta de página.

    <MultipleChoice>
    <Option isCorrect>dentro `getStaticPaths`</Option>
    <Option>fuera `getStaticPaths`</Option>
    </MultipleChoice>

2. La lista de rutas que se van a generar (devolver) mediante`getStaticPaths()`.

    <MultipleChoice>
    <Option isCorrect>dentro `getStaticPaths`</Option>
    <Option>fuera `getStaticPaths`</Option>
    </MultipleChoice>

3. Los valores recibidos de `props` y `params` que se utilizarán en la plantilla HTML.

    <MultipleChoice>
    <Option>dentro `getStaticPaths`</Option>
    <Option isCorrect>fuera `getStaticPaths`</Option>
    </MultipleChoice>
</Box>

:::note[Conclusión]
Si necesitas información para construir las rutas de la página, escríbela **dentro** de `getStaticPaths()`.

Para recibir información en la plantilla HTML de una ruta de página, escríbela **fuera** de `getStaticPaths()`.
:::


## JavaScript avanzado: Genera páginas a partir de etiquetas existentes

Tus páginas de etiquetas ahora están definidas estáticamente en `[tag].astro`.  Si agregas una nueva etiqueta a una publicación de blog, también deberás visitar esta página y actualizar las rutas de tus páginas.

El siguiente ejemplo muestra cómo sustituir el código de esta página por un código que buscará automáticamente y generará páginas para cada etiqueta utilizada en las páginas de tu blog.

:::note
Aunque parezca un reto, puedes intentar seguir los pasos para construir esta función por ti mismo. Si no quieres repasar el código JavaScript requerido en este momento, puedes saltar a la [versión final del código](#ejemplo-de-código-final) y usarlo directamente en tu proyecto, reemplazando el contenido existente.
:::

### 1. Comprueba que todas las entradas de tu blog contienen etiquetas

Revisa cada una de tus páginas Markdown existentes y asegúrate de que cada entrada contiene un array `tags` en su frontmatter. Incluso si sólo tiene una etiqueta, debe escribirse como un array, por ejemplo, `tags: ["bloguear"]`. 

### 2. Crea un array con todas las etiquetas existentes

Añade el siguiente código para obtener una lista de todas las etiquetas utilizadas en las entradas de tu blog.

  ```astro title="src/pages/tags/[tag].astro" ins={7}
  ---
  import BaseLayout from '../../layouts/BaseLayout.astro';

  export async function getStaticPaths() {
    const allPosts = await Astro.glob('../posts/*.md');
    
    const uniqueTags = [...new Set(allPosts.map((post) => post.frontmatter.tags).flat())];
  ```

    <details>
    <summary>¡Dime con más detalle qué hace esta línea de código!</summary>

   ¡Está bien si esto no es algo que hubieras escrito tú mismo todavía!

    Recorre cada entrada Markdown, una a una, y combina cada array de etiquetas en un único array más grande. A continuación, crea un nuevo `Set` a partir de todas las etiquetas individuales que ha encontrado (para ignorar los valores repetidos). Finalmente, convierte ese conjunto en un array (sin duplicaciones), que puedes usar para mostrar una lista de etiquetas en tu página.
    </details>

Ahora tienes un array `uniqueTags` con los elementos `"astro"`, `"éxitos"`, `"comunidad"`, `"bloguear"`, `"contratiempos"`, `"aprender en público"`. 

### 3. Sustituye el valor `return` de la función `getStaticPaths`

```js title="src/pages/tags/[tag].astro" del={1-8} ins={10-16}
  return [
        {params: {tag: "astro"}, props: {posts: allPosts}},
        {params: {tag: "éxitos"}, props: {posts: allPosts}},
        {params: {tag: "comunidad"}, props: {posts: allPosts}},
        {params: {tag: "bloguear"}, props: {posts: allPosts}},
        {params: {tag: "contratiempos"}, props: {posts: allPosts}},
        {params: {tag: "aprender en público"}, props: {posts: allPosts}}
      ]

  return uniqueTags.map((tag) => {
    const filteredPosts = allPosts.filter((post) => post.frontmatter.tags.includes(tag));
    return {
      params: { tag },
      props: { posts: filteredPosts },
    };
  });
```
Una función `getStaticPaths` siempre debe devolver una lista de objetos que contengan `params` (cómo llamar a cada ruta de página) y opcionalmente cualquier `props` (datos que quieras pasar a esas páginas). Anteriormente, definiste cada nombre de etiqueta que sabías que se usaba en tu blog y pasaste toda la lista de entradas como props a cada página.

Ahora, generas esta lista de objetos automáticamente utilizando tu array `uniqueTags` para definir cada parámetro.

Y, ahora la lista de todas las publicaciones del blog es filtrada **antes** de ser enviada a cada página como props. Asegúrate de eliminar la línea de código anterior que filtra las publicaciones, y actualiza tu plantilla HTML para usar `posts` en lugar de `filteredPosts`.

```astro title="src/pages/tags/[tag].astro" del={3,7} ins={8}
const { tag } = Astro.params;
const { posts } = Astro.props;
const filteredPosts = posts.filter((post) => post.frontmatter.tags?.includes(tag));
---
<!-- -->
<ul>
    {filteredPosts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
    {posts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
</ul>
```

### Ejemplo de código final

Para comprobar tu trabajo, o si simplemente quieres un código completo y correcto para copiar en `[tag].astro`, aquí tienes el aspecto que debería tener tu componente de Astro:

```astro title="src/pages/tags/[tag].astro"
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import BlogPost from '../../components/BlogPost.astro';

export async function getStaticPaths() {
  const allPosts = await Astro.glob('../posts/*.md');
  
  const uniqueTags = [...new Set(allPosts.map((post) => post.frontmatter.tags).flat())];

  return uniqueTags.map((tag) => {
    const filteredPosts = allPosts.filter((post) => post.frontmatter.tags.includes(tag));
    return {
      params: { tag },
      props: { posts: filteredPosts },
    };
  });
}

const { tag } = Astro.params;
const { posts } = Astro.props;
---
<BaseLayout pageTitle={tag}>
  <p>Posts etiquetados con {tag}</p>
  <ul>
    {posts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
  </ul>
</BaseLayout>
```

Ahora, deberías poder visitar cualquiera de tus páginas de etiquetas en la vista previa de tu navegador.

Navega a `http://localhost:4321/tags/comunidad` y verás una lista sólo de las entradas de tu blog con la etiqueta `comunidad`. Del mismo modo, `http://localhost:4321/tags/aprender%20en%20público` debería mostrar una lista de las entradas del blog con la etiqueta `aprender en público`.

En la siguiente sección, crearás enlaces de navegación a estas páginas.



<Box icon="question-mark">

### Pon a prueba tus conocimientos

Elije el término que corresponda a la descripción.

1. Función que devuelve un array de rutas de páginas.

    <MultipleChoice>
      <Option>params</Option>
      <Option>enrutamiento dinámico</Option>
      <Option isCorrect>`getStaticPaths()`</Option>
      <Option>props</Option>
    </MultipleChoice>

2. El proceso de creación de varias rutas de páginas a partir de un archivo en Astro.

    <MultipleChoice>
      <Option>params</Option>
      <Option isCorrect>enrutamiento dinámico</Option>
      <Option>`getStaticPaths()`</Option>
      <Option>props</Option>
    </MultipleChoice>

4. Valor que define el nombre de una ruta de página generada dinámicamente.

    <MultipleChoice>
      <Option isCorrect>params</Option>
      <Option>enrutamiento dinámico</Option>
      <Option>`getStaticPaths()`</Option>
      <Option>props</Option>
    </MultipleChoice>

</Box>

<Box icon="check-list">

## Checklist

<Checklist>
- [ ] Puedo generar páginas dinámicamente.
- [ ] Puedo pasar `props` a cada ruta de página.
</Checklist>
</Box>

### Recursos

- [Enrutamiento dinámico de páginas en Astro](/es/guides/routing/#rutas-dinámicas)

- [documentación de la API `getStaticPaths()`](/es/reference/api-reference/#getstaticpaths)
